For this assignment, implement the Recursive Best-First Search
implementation of the A* algorithm given in class. Name this function Astar_search
. Also in this notebook include your iterative_deepening_search
functions.
Define a new function named effective_branching_factor
that returns an estimate of the effective
branching factor for a search algorithm applied to a search problem.
So, the required functions are
Astar_search(start_state, actions_f, take_action_f, goal_test_f, h_f)
iterative_deepening_search(start_state, goal_state, actions_f, take_action_f, max_depth)
effective_branching_factor(n_nodes, depth, precision=0.01)
, returns the effective branching factor, given the number of nodes expanded and depth reached during a search.Apply iterative_deepening_search
and Astar_search
to several eight-tile sliding puzzle
problems. For this you must include your implementations of these functions from Assignment 2. Here we are renaming these functions to not include _f
, just for simplicity.
actions_8p(state)
: returns a list of up to four valid actions that can be applied in state
. With each action include a step cost of 1. For example, if all four actions are possible from this state, return [('left', 1), ('right', 1), ('up', 1), ('down', 1)].take_action_8p(state, action)
: return the state that results from applying action
in state
and the cost of the one step,plus the following function for the eight-tile puzzle:
goal_test_8p(state, goal)
Compare their results by displaying solution path depth, number of nodes generated, and the effective branching factor, and discuss the results. Do this by defining the following function that prints the table as shown in the example below.
run_experiment(goal_state_1, goal_state_2, goal_state_3, [h1, h2, h3])
Define this function so it takes any number of $h$ functions in the list that is the fourth argument.
For Astar_search
use the following two heuristic functions, plus one more of your own design, for a total of three heuristic functions.
h1_8p(state, goal)
: $h(state, goal) = 0$, for all states $state$ and all goal states $goal$,h2_8p(state, goal)
: $h(state, goal) = m$, where $m$ is the Manhattan distance that the blank is from its goal position,h3_8p(state, goal)
: $h(state, goal) = ?$, that you define. It must be admissible, and not constant for all states.Apply all four algorithms (iterative_deepening_search
plus Astar_search
with the three heuristic
functions) to three eight-tile puzzle problems with start state
and these three goal states.
$$ \begin{array}{ccccccccccc} 1 & 2 & 3 & ~~~~ & 1 & 2 & 3 & ~~~~ & 1 & 0 & 3\\ 4 & 0 & 5 & & 4 & 5 & 8 & & 4 & 5 & 8\\ 6 & 7 & 8 & & 6 & 0 & 7 & & 2 & 6 & 7 \end{array} $$Print a well-formatted table like the following. Try to match this
format. If you have time, you might consider learning a bit about the DataFrame
class in the pandas
package. When displayed in jupyter notebooks, pandas.DataFrame
objects are nicely formatted in html.
[1, 2, 3, 4, 0, 5, 6, 7, 8] [1, 2, 3, 4, 5, 8, 6, 0, 7] [1, 0, 3, 4, 5, 8, 2, 6, 7]
Algorithm Depth Nodes EBF Depth Nodes EBF Depth Nodes EBF
IDS 0 0 0.000 3 43 3.086 11 225850 2.954
A*h1 0 0 0.000 3 116 4.488 11 643246 3.263
A*h2 0 0 0.000 3 51 3.297 11 100046 2.733
Of course you will have one more line for h3
.
First, some example output for the effective_branching_factor function. During execution, this example shows debugging output which is the low and high values passed into a recursive helper function.
effective_branching_factor(10, 3)
1 10 1 5.5 1 3.25 1 2.125 1.5625 2.125 1.5625 1.84375 1.5625 1.703125 1.6328125 1.703125 1.6328125 1.66796875 1.650390625 1.66796875 1.6591796875 1.66796875 1.6591796875 1.66357421875
1.661376953125
The smallest argument values should be a depth of 0, and 1 node.
effective_branching_factor(1, 0)
1 1
1.0
effective_branching_factor(2, 1)
1 2 1 1.5 1 1.25 1 1.125 1 1.0625 1 1.03125 1 1.015625
1.0078125
effective_branching_factor(2, 1, precision=0.000001)
1 2 1 1.5 1 1.25 1 1.125 1 1.0625 1 1.03125 1 1.015625 1 1.0078125 1 1.00390625 1 1.001953125 1 1.0009765625 1 1.00048828125 1 1.000244140625 1 1.0001220703125 1 1.00006103515625 1 1.000030517578125 1 1.0000152587890625 1 1.0000076293945312 1 1.0000038146972656 1 1.0000019073486328
1.0000009536743164
effective_branching_factor(200000, 5)
1 200000 1 100000.5 1 50000.75 1 25000.875 1 12500.9375 1 6250.96875 1 3125.984375 1 1563.4921875 1 782.24609375 1 391.623046875 1 196.3115234375 1 98.65576171875 1 49.827880859375 1 25.4139404296875 1 13.20697021484375 7.103485107421875 13.20697021484375 10.155227661132812 13.20697021484375 10.155227661132812 11.681098937988281 10.918163299560547 11.681098937988281 10.918163299560547 11.299631118774414 11.10889720916748 11.299631118774414 11.204264163970947 11.299631118774414 11.25194764137268 11.299631118774414 11.25194764137268 11.275789380073547 11.263868510723114 11.275789380073547 11.26982894539833 11.275789380073547 11.272809162735939 11.275789380073547 11.274299271404743 11.275789380073547 11.275044325739145 11.275789380073547 11.275416852906346 11.275789380073547 11.275416852906346 11.275603116489947 11.275509984698147 11.275603116489947 11.275556550594047 11.275603116489947 11.275579833541997 11.275603116489947 11.275591475015972 11.275603116489947 11.275591475015972 11.27559729575296 11.275594385384466 11.27559729575296 11.275595840568712 11.27559729575296 11.275596568160836 11.27559729575296
11.275596931956898
effective_branching_factor(200000, 50)
1 200000 1 100000.5 1 50000.75 1 25000.875 1 12500.9375 1 6250.96875 1 3125.984375 1 1563.4921875 1 782.24609375 1 391.623046875 1 196.3115234375 1 98.65576171875 1 49.827880859375 1 25.4139404296875 1 13.20697021484375 1 7.103485107421875 1 4.0517425537109375 1 2.5258712768554688 1 1.7629356384277344 1 1.3814678192138672 1.1907339096069336 1.3814678192138672 1.1907339096069336 1.2861008644104004 1.1907339096069336 1.238417387008667 1.2145756483078003 1.238417387008667 1.2264965176582336 1.238417387008667 1.2324569523334503 1.238417387008667 1.2324569523334503 1.2354371696710587 1.2339470610022545 1.2354371696710587 1.2346921153366566 1.2354371696710587 1.2346921153366566 1.2350646425038576 1.2346921153366566 1.234878378920257 1.2347852471284568 1.234878378920257 1.2347852471284568 1.234831813024357 1.234808530076407 1.234831813024357 1.234808530076407 1.234820171550382 1.2348143508133944 1.234820171550382 1.2348172611818882 1.234820171550382 1.234818716366135 1.234820171550382 1.234818716366135 1.2348194439582585 1.2348190801621968 1.2348194439582585 1.2348190801621968 1.2348192620602276 1.2348191711112122 1.2348192620602276 1.23481921658572 1.2348192620602276 1.2348192393229738 1.2348192620602276 1.2348192393229738 1.2348192506916007 1.2348192450072872 1.2348192506916007 1.234819247849444 1.2348192506916007
1.2348192492705223
Here is a simple example using our usual simple graph search.
def actions_simple(state):
succs = {'a': ['b', 'c'], 'b':['a'], 'c':['h'], 'h':['i'], 'i':['j', 'k', 'l'], 'k':['z']}
return [(s, 1) for s in succs.get(state, [])]
def take_action_simple(state, action):
return action
def goal_test_simple(state, goal):
return state == goal
def h_simple(state, goal):
return 1
actions = actions_simple('a')
actions
[('b', 1), ('c', 1)]
take_action_simple('a', actions[0])
('b', 1)
goal_test_simple('a', 'a')
True
h_simple('a', 'z')
1
iterative_deepening_search('a', 'z', actions_simple, take_action_simple, 10)
['a', 'c', 'h', 'i', 'k', 'z']
Astar_search('a',actions_simple, take_action_simple,
lambda s: goal_test_simple(s, 'z'),
lambda s: h_simple(s, 'z'))
(['a', 'c', 'h', 'i', 'k', 'z'], 5)
Download A3grader.tar and extract A3grader.py from it.
%run -i A3grader.py
======================= Code Execution ======================= Extracting python code from notebook named 'Anderson-A3.ipynb' and storing in notebookcode.py Removing all statements that are not function or class defs or import statements. Testing actions_8p([1, 2, 3, 4, 5, 6, 7, 0, 8]) --- 5/5 points. Your actions_8p correctly returned [('left', 1), ('right', 1), ('up', 1)] Testing take_action_8p([1, 2, 3, 4, 5, 6, 7, 0, 8], (up, 1)) --- 5/5 points. Your take actions_8p correctly returned ([1, 2, 3, 4, 0, 6, 7, 5, 8], 1) Testing goal_test_8p([1, 2, 3, 4, 5, 6, 7, 0, 8], [1, 2, 3, 4, 5, 6, 7, 0, 8]) --- 5/5 points. Your goal_test_8p correctly True Testing Astar_search(1, 2, 3, 4, 5, 6, 7, 0, 8], actions_8p, take_action_8p, lambda s: goal_test_8p(s, [0, 2, 3, 1, 4, 6, 7, 5, 8]), lambda s: h1_8p(s, [0, 2, 3, 1, 4, 6, 7, 5, 8])) --- 20/20 points. Your search correctly returned ([[1, 2, 3, 4, 5, 6, 7, 0, 8], [1, 2, 3, 4, 0, 6, 7, 5, 8], [1, 2, 3, 0, 4, 6, 7, 5, 8], [0, 2, 3, 1, 4, 6, 7, 5, 8]], 3) Testing iterative_deepening_search([1, 2, 3, 4, 5, 6, 7, 0, 8], [0, 2, 3, 1, 4, 6, 7, 5, 8], actions_8p, take_action_8p, 10) --- 15/15 points. Your search correctly returned [[1, 2, 3, 4, 5, 6, 7, 0, 8], [1, 2, 3, 4, 0, 6, 7, 5, 8], [1, 2, 3, 0, 4, 6, 7, 5, 8], [0, 2, 3, 1, 4, 6, 7, 5, 8]] Testing iterative_deepening_search([5, 2, 8, 0, 1, 4, 3, 7, 6], [0, 2, 3, 1, 4, 6, 7, 5, 8], actions_8p, take_action_8p, 10) --- 15/15 points. Your search correctly returned cutoff Testing effective_branching_factor(200, 6, 0.1) --- 15/15 points. Your call to effective_branching_factor correctly returned 2.185373306274414 ====================================================================== A3 Execution Grade is 80 / 80 ====================================================================== ___ / 10 points. At least 6 meaningful sentences describing your third heuristic function. Describe what it calculates and argue why you think it is admissible. ___ / 10 points. At least 6 more sentences that discuss the similarities and differences in your results for each search method and heuristic function. ====================================================================== A3 Additional Grade is __ / 20 ====================================================================== ====================================================================== A3 FINAL GRADE is _ / 100 ====================================================================== Extra Credit: Earn one point of extra credit for adding the computation time to your results table and a discussion of the timing results. A3 EXTRA CREDIT is 0 / 1
Add a third column for each result (from running runExperiment
) that is the number of seconds each search required. You may get the total run time when running a function by doing
import time
start_time = time.time()
< do some python stuff >
end_time = time.time()
print('This took', end_time - start_time, 'seconds.')